<?php

namespace app\service;

use support\Redis;

class BucketLimiter
{
    protected static $maxTokens=120;
    protected static $availableTokens = 100;
    protected static $startMilli;
    protected static $rate;
    protected static $maxWaitTime = 100;
    protected static $intervalTokenMilli;
    protected static $timeout = 60;

    /**
     * 漏桶
     * @param $requierdToken
     * @param $id
     * @return bool
     */
    public static function getLeakyBucketToken($requierdToken, $id)
    {
        //$now       = self::getNowTime();
        $now       = time();
        $num       = Redis::get('lbkt:num:' . $id);
        $startTime = Redis::get('lbkt:start:' . $id);
        if ($startTime) {
            self::$availableTokens = $num;
            self::$startMilli      = $startTime;
            // 先执行漏令牌，计算剩余令牌量
            self::$availableTokens = max(0, (self::$availableTokens) - ($now - (self::$startMilli)) * (self::$rate));
        }

        if (((self::$availableTokens) + $requierdToken) < (self::$maxTokens)) {
            // 尝试加令牌,并且令牌还未满
            self::$availableTokens += $requierdToken;
            Redis::setEx('lbkt:num:' . $id,self::$timeout, self::$availableTokens);
            Redis::setEx('lbkt:start:' . $id,self::$timeout, $now);
        } else {
            // 桶满，拒绝加令牌
            return ['code' => 1, 'msg' => '请稍后再试！'];
        }
    }

    private static function getNowTime()
    {
        list($s1, $s2) = explode(' ', microtime());
        return (float) sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
    }
}
